package com.springboot.frame.excel.handler;

import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.*;

/**
 * @author madman
 */
@Slf4j
public final class CellTypeManager {

  /**
   * 处理器缓存Map
   */
  private static final Map<Class<?>, CellHandler> HANDLER_CACHE = new HashMap<>();
  /**
   * 时间类型集
   */
  private static final List<Class<? extends Date>> DATE_TYPE = Arrays
      .asList(Date.class, java.sql.Date.class, Time.class, Timestamp.class);
  /**
   * 精度类型集
   */
  private static final List<?> PRECISION_TYPE = Arrays
      .asList(float.class, Float.class, double.class, Double.class, BigDecimal.class);

  static {
    register(PrecisionCellHandler.INSTANCE, float.class, Float.class, double.class, Double.class,
        BigDecimal.class);
    register(DateCellHandler.INSTANCE, Date.class, java.sql.Date.class, Time.class,
        Timestamp.class);
    register(BooleanCellHandler.INSTANCE, boolean.class, Boolean.class);
    register(PrimitiveCellHandler.INSTANCE, short.class, Short.class, int.class, Integer.class,
        long.class, Long.class,
        BigInteger.class);
    register(StringCellHandler.INSTANCE, String.class, Object.class, Character.class);
  }

  private CellTypeManager() {
  }

  /**
   * 获取处理器
   *
   * @param clazz Class类型
   * @return 该Class类型对应的处理器
   */
  public static CellHandler getHandler(Class<?> clazz) {
    CellHandler cellHandler = HANDLER_CACHE.get(clazz);
    if (cellHandler == null) {
      if (clazz.isEnum()) {
        if (EnumValueProvider.class.isAssignableFrom(clazz)) {
          return CustomEnumCellHandler.INSTANCE;
        }
        return DefaultEnumNameCellHandler.INSTANCE;
      }
      return StringCellHandler.INSTANCE;
    }
    return cellHandler;
  }

  /**
   * 注册处理器
   *
   * @param cellHandler 处理器
   * @param classes Class类型集
   */
  public static void register(CellHandler cellHandler, Class<?>... classes) {
    for (Class<?> clazz : classes) {
      HANDLER_CACHE.put(clazz, cellHandler);
      log.debug("global register handler {} for {}", cellHandler, clazz.getName());
    }
  }

  /**
   * 判断是否是时间类型
   *
   * @param type Class类型
   * @return 该Class类型是否是时间类型
   */
  public static boolean isDateType(Class<?> type) {
    return DATE_TYPE.contains(type);
  }

  /**
   * 判断是否是精度类型
   *
   * @param type Class类型
   * @return 该Class类型是否是精度类型
   */
  public static boolean isPrecisionType(Class<?> type) {
    return PRECISION_TYPE.contains(type);
  }

}
